from flask import Flask, render_template, request, session, redirect, url_for, flash
from flask_socketio import SocketIO, join_room, leave_room
from flask_pymongo import PyMongo
import db_utils
import time

#create web service
app = Flask(__name__)

#database config
app.config["MONGO_URI"] = "mongodb://localhost:27017/ChatDB"
mongo = PyMongo(app)
app.config['SECRET_KEY'] = '123'

#initiallize socketio
socketio = SocketIO()
socketio.init_app(app)

#initiallize admin account
checkadmin = db_utils.get_user_data(mongo.db["User"],{"username":"admin"})
if checkadmin is None:
    db_utils.create_user(mongo.db["User"],{"username":"admin","password":"admin","group":"admin"})

# store online info
online_user=[]
all_rooms={}

#login page
@app.route('/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':

        #already login
        if 'admin' in session:
            return redirect(url_for('admin'))
        elif 'username' in session:
            return redirect(url_for('homepage'))
        
        return render_template('index.html')
    else:
        username = request.form.get('username')
        password = request.form.get('password')

        #login check
        userdata = db_utils.get_user_data(mongo.db["User"],{"username":username})

        #user not found
        if userdata is None:
            print("User not found")

            #return error message
            flash("User not found","no_user_error")
            return redirect(url_for('register'))

        #login sucess
        elif userdata["password"] == password:

            #admin login
            if userdata["group"]=="admin":
                print("admin login sucess")
                session["username"]=username
                session["admin"]=1
                #redirect to user homepage
                return redirect(url_for('admin'))
            
            #user login
            else:
                print("login sucess")
                session["username"]=username
                #redirect to user homepage
                return redirect(url_for('homepage'))

        #wrong password
        else:
            print("wrong password")

            #return error message
            flash("login failed","password_error")
            return render_template('index.html')

#register page
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('register.html')
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        confirm_pass = request.form.get('confirm_pass')

        #confirm password
        if confirm_pass == password:

            #check duplicate username
            userdata = db_utils.get_user_data(mongo.db["User"],{"username":username})
            if userdata is None:
                print("register sucess")

                #create new user
                result = db_utils.create_user(mongo.db["User"],{"username":username,"password":password,"group":"user"})
                print(result)

                #success message
                flash("register sucess","register_sucess")
                return redirect(url_for('login'))
            
            #user already exist
            else:
                print("register failed")

                #return error message
                flash("register failed","duplicated_user_error")
                return render_template('register.html')
        
        #password not match
        else:
            flash("password not match","pass_notmatch_error")
            return render_template('register.html')

#homepage
@app.route('/homepage', methods=['GET', 'POST'])
def homepage():
    if request.method == 'GET':
        if 'username' in session:
            username = session['username']
            return render_template('homepage.html', username=username, all_rooms = all_rooms)
        else:
            return redirect(url_for('login'))

#enter room
@app.route('/homepage_enter/', methods=['POST'])
def homepage_enter():
    if request.method == 'POST':
        roomname = request.form.get('selected_room')
        username = session['username']
        #get current timestamp
        t = time.localtime()
        timestamp = "["+str(t.tm_year)+"/"+str(t.tm_mon)+"/"+str(t.tm_mday)+" "+str(t.tm_hour)+":"+str(t.tm_min)+":"+str(t.tm_sec)+"]"
        #record logs
        db_utils.insert_history(mongo.db["History"],timestamp+username+" entered room from "+request.remote_addr)
        return render_template('chatroom.html', username=username, room=roomname)

#create room
@app.route('/homepage_create/', methods=['POST'])
def homepage_create():
    if request.method == 'POST':
        roomname = request.form.get('roomname')
        username = session['username']
        #get current timestamp
        t = time.localtime()
        timestamp = "["+str(t.tm_year)+"/"+str(t.tm_mon)+"/"+str(t.tm_mday)+" "+str(t.tm_hour)+":"+str(t.tm_min)+":"+str(t.tm_sec)+"]"
        #record logs
        db_utils.insert_history(mongo.db["History"],timestamp+username+" entered room from "+request.remote_addr)
        return render_template('chatroom.html', username=username, room=roomname)

#logout
@app.route('/logout/',methods=['POST'])
def logout():
    print("logout")
    if 'username' in session:
        session.clear()
        print("session cleared")
    return redirect(url_for('login'))

#jump to edit profile
@app.route('/jpto_edit_profile/',methods=['POST'])
def jpto_edit_profile():
    return redirect(url_for('editprofile'))

#edit profile page
@app.route('/editprofile', methods=['GET', 'POST'])
def editprofile():
    if request.method == 'GET':
        if 'username' in session:
            username = session['username']
            return render_template('editprofile.html', username=username)
        else:
            return redirect(url_for('login'))
        
#change password
@app.route('/change_pass', methods=['POST'])
def change_pass():
    if request.method == 'POST':
        username = session['username']
        password = request.form.get('password')
        confirm_pass = request.form.get('confirm_pass')

        #confirm password
        if confirm_pass == password:
            db_utils.update_user(mongo.db["User"],username,"password",password)
            print("password updated!")
            flash("password updated!","change_pass_sucess")
            return render_template('editprofile.html')
        
        #password not match
        else:
            flash("password not match","pass_notmatch_error")
            return render_template('editprofile.html')

#delete account
@app.route('/del_account', methods=['POST'])
def del_account():
    if request.method == 'POST':
        username = session['username']
        db_utils.delete_user(mongo.db["User"],{"username":username})
        print("user deleted!")
        session.clear()
        print("session cleared")
        flash("user deleted!","del_user_sucess")
        return redirect(url_for('login'))

#admin page
@app.route('/admin', methods=['GET', 'POST'])
def admin():
    if request.method == 'GET':
        if 'username' in session and 'admin' in session:
            admin_username = session['username']
            return render_template('admin.html', username=admin_username)
        else:
            return redirect(url_for('login'))
    else:
        operation = request.form.get('operation')
        username = request.form.get('username')
        password = request.form.get('password')
        group = request.form.get('group')

        #check user
        userdata = db_utils.get_user_data(mongo.db["User"],{"username":username})

        #create new account
        if operation == '1':
            if userdata is None:
                result = db_utils.create_user(mongo.db["User"],{"username":username,"password":password,"group":group})
                print(result)
                return render_template('admin.html')
            
            #user already exist
            else:
                print("register failed")
                #return error message
                flash("register failed","duplicated_user_error")
                return render_template('admin.html')

        
        #edit account
        elif operation == '2':
            #user not found
            if userdata is None:
                print("User not found")
                #return error message
                flash("User not found","no_user_error")
                return render_template('admin.html')
            result1 = db_utils.update_user(mongo.db["User"],username,"password",password)
            result2 = db_utils.update_user(mongo.db["User"],username,"group",group)
            print(result1)
            print(result2)
            return render_template('admin.html')
        
        #delete account
        else:
            #user not found
            if userdata is None:
                print("User not found")
                #return error message
                flash("User not found","no_user_error")
                return render_template('admin.html')
            
            #avoid deleting default admin account
            elif userdata["username"]=="admin":
                flash("error","cannot_del_error")
                return render_template('admin.html')

            #admin self delete
            elif userdata["username"] == session["username"]:
                session.clear()
                flash("success_del","del_admin_sucess")
                return redirect(url_for('login'))
            
            
            result3 = db_utils.delete_user(mongo.db["User"],{"username":username})
            print(result3)
            return render_template('admin.html')

#leave room button
@app.route('/leaveroom', methods=['POST','GET'])
def leaveroom():
    return redirect(url_for('homepage'))

#socket io services
#establish websocket connection with server
@socketio.on('connect')
def handle_connect():
    username = session.get('username')
    online_user.append(username)

#join room
@socketio.on('join')
def on_join(data):
    username = data.get('username')
    room = data.get('room')
    try:
        all_rooms[room].append(username)
    except:
        all_rooms[room] = []
        all_rooms[room].append(username)

    join_room(room)
    #get current timestamp
    t = time.localtime()
    timestamp = "["+str(t.tm_year)+"/"+str(t.tm_mon)+"/"+str(t.tm_mday)+" "+str(t.tm_hour)+":"+str(t.tm_min)+":"+str(t.tm_sec)+"]"
    #record logs
    db_utils.insert_history(mongo.db["History"],timestamp+username+" entered room "+room)
    socketio.emit('connect info', username + ' joined room', to=room)
    socketio.emit("update online users", all_rooms[room], to=room)

#send message
@socketio.on('send msg')
def handle_message(data):
    print('sendMsg' + str(data))
    room = session.get('room')
    data['message'] = data.get('message').replace('<', '&lt;').replace('>', '&gt;').replace(' ', '&nbsp;')
    #get current timestamp
    t = time.localtime()
    timestamp = "["+str(t.tm_year)+"/"+str(t.tm_mon)+"/"+str(t.tm_mday)+" "+str(t.tm_hour)+":"+str(t.tm_min)+":"+str(t.tm_sec)+"]"
    #record logs
    db_utils.insert_history(mongo.db["History"],timestamp+data.get('user')+" : "+data.get('message'))
    socketio.emit('update msg', data, to=room)

#leave room
@socketio.on('leave')
def on_leave(data):
    username = data.get('username')
    room = data.get('room')
    all_rooms[room].remove(username)
    leave_room(room)
    #get current timestamp
    t = time.localtime()
    timestamp = "["+str(t.tm_year)+"/"+str(t.tm_mon)+"/"+str(t.tm_mday)+" "+str(t.tm_hour)+":"+str(t.tm_min)+":"+str(t.tm_sec)+"]"
    #record logs
    db_utils.insert_history(mongo.db["History"],timestamp+username+" leaved room "+room)
    socketio.emit('connect info', username + ' leaved room', to=room)
    socketio.emit("update online users", all_rooms[room], to=room)

#start service
if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5000, debug=True, allow_unsafe_werkzeug=True)